package lib.pacificapp.util;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
   

import android.annotation.SuppressLint; 
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message; 
import android.util.Log;

/**
 * <br/> <br/>
 * AsyncImageLoader.java 
 *         2012-9-23
 * 
 */
public class ImageLoader { 
	 public static final int SUCCESS=1;
	 public static final int CACHE=2;
	 public static final int ERROR=-1;
	 public interface ResourceCallback{
		    void onComplete(int status,String url,Drawable data);
		 
	 }
 	 private static final int THREAD_COUNT = 5; 
 	private static ImageLoader asyncImageLoader = null;
 
	private ExecutorService mService = null;

	private ImageLoader() {
		mService = Executors.newFixedThreadPool(THREAD_COUNT);
	}
	public String getApplicationName(Context activity) { 
		PackageManager packageManager = null; 
		ApplicationInfo applicationInfo = null; 
		try { 
		packageManager = activity.getApplicationContext().getPackageManager(); 
		applicationInfo = packageManager.getApplicationInfo(activity.getPackageName(), 0); 
		} catch (PackageManager.NameNotFoundException e) { 
		applicationInfo = null; 
		} 
		String applicationName = 
		(String) packageManager.getApplicationLabel(applicationInfo); 
		return applicationName; 
		} 
	public Drawable loadDrawable(Context context,String imageUrl,boolean thum,ResourceCallback callback) {
		 String path = Filer.getIntance().getSDOrCache(context,"/.pacache/")+Filer.getIntance().formatPath(imageUrl);
		 
		 return loadDrawable(imageUrl, path, false,thum, callback);
	}
	 
	public static ImageLoader getInstance() {
		if (asyncImageLoader == null) {
			asyncImageLoader = new ImageLoader();
		}
		return asyncImageLoader;
	}

	 
	private Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();

	 
	public Drawable loadDrawable(final String imageUrl, final String path, final ResourceCallback callback) {
		return loadDrawable(imageUrl, path, false,false, callback);
	}
	
 
	@SuppressLint("HandlerLeak")
	private Drawable loadDrawable(final String imageUrl, final String path,
			                   final boolean isUseCache,final boolean thum, final ResourceCallback callback) {
	//	if(StringUtil.isBlank(imageUrl) || !imageUrl.startsWith("http")) return null;
		if (isUseCache && imageCache.containsKey(imageUrl)) {
			SoftReference<Drawable> softReference = imageCache.get(imageUrl);
			if (softReference.get() != null) {
				callback.onComplete(CACHE,imageUrl,softReference.get() );
				return softReference.get();
			}
		}
		final Handler handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				if (msg.obj != null)
					callback.onComplete(SUCCESS,imageUrl,(Drawable)msg.obj);
			}
		};
		mService.submit(new Runnable() {
			public void run() {
				Drawable drawable = getDrawableFromCache(imageUrl, path,thum);
				if (drawable == null) {
					try {
						saveInputStream(imageUrl, path);
						drawable = getDrawableFromCache(imageUrl, path,thum);
						if (drawable == null) { 
							saveInputStream(imageUrl, path);
							drawable = getDrawableFromCache(imageUrl, path,thum);
						}
					} catch (IOException e1) {
						//e1.printStackTrace();
						drawable = null;
					}
				}
				 
				if (isUseCache && drawable != null) {
					imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
				}
				 if (drawable != null){
					handler.sendMessage(handler.obtainMessage(0, drawable));
				}
					drawable = null;
			};
		});
		return null;
	}

 
	@SuppressLint("HandlerLeak")
	private Bitmap loadBitmap(final Context context, final String imageUrl, final String path,final boolean thum, final ResourceCallback callback) {
	//	if(StringUtil.isBlank(imageUrl) || !imageUrl.startsWith("http")) return null;
		final Handler handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				if (msg.obj != null)
					callback.onComplete(SUCCESS,imageUrl,(Drawable) msg.obj);
			}
		};
		mService.submit(new Runnable() {
			public void run() {
				Bitmap bitmap = getBitmapFromCache(imageUrl, path,thum);
				if (bitmap == null) {
					try {
						saveInputStream(imageUrl, path);
						bitmap = getBitmapFromCache( imageUrl, path,thum);
						if (bitmap == null) {
							 Thread.sleep(500);
							saveInputStream(imageUrl, path);
							bitmap = getBitmapFromCache(imageUrl, path,thum);
						}
					} catch (IOException e1) {
						e1.printStackTrace();
						bitmap = null;
					}
				 
					catch (InterruptedException e) {
						e.printStackTrace();
						bitmap = null;
					}
				}
				handler.sendMessage(handler.obtainMessage(0, bitmap));
				if (bitmap != null)
					bitmap = null;
			};
		});
		return null;
	}

	/** 
	 * 
	 * @param context 
	 */
	private void saveInputStream(String imageUrl, String path) throws IOException {
		InputStream is = null;
		HttpURLConnection conn = null;
		FileOutputStream fos = null;
		File file = new File(path);
		if (!file.exists()) {
			try {
				conn = (HttpURLConnection) new URL(imageUrl).openConnection();
				conn.setConnectTimeout(20000);
				conn.setReadTimeout(20000);
				conn.setRequestMethod("GET");
				conn.connect();
				is = conn.getInputStream();
				
				fos = new FileOutputStream(file);
				int size = 0;
				byte[] buffer = new byte[1024];
				while ((size = is.read(buffer)) != -1)
					fos.write(buffer, 0, size);
				fos.flush();
				fos.close();
			} catch (FileNotFoundException e) {
				//e.printStackTrace();
			} catch (IOException e) {
				//e.printStackTrace();
			} finally {
				try {
					if (fos != null) {
						fos.close();
						fos = null;
					}
					if (file != null)
						file = null;
					if (conn != null)
						conn.disconnect();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
 
	private Drawable getDrawableFromCache( String imageurl, String path,boolean thum) {
		if (imageurl == null || imageurl.equals(""))
			return null;
		File file = new File(path);
		Drawable data=null;
		if (!file.exists())
			return null;
		try {
			 file.setLastModified(System.currentTimeMillis());
			 data= (Drawable) (new BitmapDrawable(getBitmapFromCache(imageurl, path,thum)));// Drawable.createFromPath(file.getAbsolutePath());
		} catch (Exception e) {
			  
		}  
		 
		return data;
	}
	 
	private int zoom;
	/**  */
	private Bitmap getBitmapFromCache(String imageurl, String path,boolean thum) {
		 BitmapFactory.Options opt = new BitmapFactory.Options();
	        opt.inJustDecodeBounds = true;
	     BitmapFactory.decodeFile(path, opt);
	     return  tryGetBitmap(path,opt.outWidth,thum?4444:444326);
	 }

	private int width = 0;
 
	public int width() {
		  return width;
	    
	}
 
	  
	
	public static Bitmap tryGetBitmap(String imgFile, int minSideLength,  
	        int maxNumOfPixels) {  
	    if (imgFile == null || imgFile.length() == 0)  
	        return null;  
	  
	    try {  
	        FileDescriptor fd = new FileInputStream(imgFile).getFD();  
	        BitmapFactory.Options options = new BitmapFactory.Options();  
	        options.inJustDecodeBounds = true;  
	        options.inSampleSize=2;
	        options.inTempStorage = new byte[1024*1024*5];
	      
	        BitmapFactory.decodeFileDescriptor(fd, null, options);  
	  
	        options.inSampleSize = computeSampleSize(options, minSideLength,  
	                maxNumOfPixels);  
	        Log.d("mt_imagesize",options.inSampleSize+"");
	        try {  
	            // 这里一定要将其设置回false，因为之前我们将其设置成了true  
	            // 设置inJustDecodeBounds为true后，decodeFile并不分配空间，即，BitmapFactory解码出来的Bitmap为Null,但可计算出原始图片的长度和宽度  
	            options.inJustDecodeBounds = false;  
	  
	            Bitmap bmp = BitmapFactory.decodeFile(imgFile, options);  
	            return bmp == null ? null : bmp;  
	        } catch (OutOfMemoryError err) {  
	        	  Log.d("mt_debug", "OutOfMemoryError");
	         	  err.printStackTrace();
	         	  Log.d("mt_debug", "OutOfMemoryError END");
	              return null;  
	        }  
	    } catch (Exception e) {  
	        return null;  
	    }  
	}  
	/** 
	 * compute Sample Size 
	 *  
	 * @param options 
	 * @param minSideLength 
	 * @param maxNumOfPixels 
	 * @return 
	 */  
	public static int computeSampleSize(BitmapFactory.Options options,  
	        int minSideLength, int maxNumOfPixels) {  
	    int initialSize = computeInitialSampleSize(options, minSideLength,  
	            maxNumOfPixels);  
	  
	    int roundedSize;  
	    if (initialSize <= 8) {  
	        roundedSize = 1;  
	        while (roundedSize < initialSize) {  
	            roundedSize <<= 1;  
	        }  
	    } else {  
	        roundedSize = (initialSize + 7) / 8 * 8;  
	    }  
	  
	    return roundedSize;  
	}  
	  
	/** 
	 * compute Initial Sample Size 
	 *  
	 * @param options 
	 * @param minSideLength 
	 * @param maxNumOfPixels 
	 * @return 
	 */  
	private static int computeInitialSampleSize(BitmapFactory.Options options,  
	        int minSideLength, int maxNumOfPixels) {  
	    double w = options.outWidth;  
	    double h = options.outHeight;  
	    // 上下限范围  
	    int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math  
	            .sqrt(w * h / maxNumOfPixels));  
	    int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(  
	            Math.floor(w / minSideLength), Math.floor(h / minSideLength));  
	  
	    if (upperBound < lowerBound) {  
	        // return the larger one when there is no overlapping zone.  
	        return lowerBound;  
	    }  
	  
	    if ((maxNumOfPixels == -1) && (minSideLength == -1)) {  
	        return 1;  
	    } else if (minSideLength == -1) {  
	        return lowerBound;  
	    } else {  
	        return upperBound;  
	    }  
	}

	public int getZoom() {
		if(zoom==0)zoom=2;
		return zoom;
	}

	public void setZoom(int zoom) {
		this.zoom = zoom;
	}  
}